Als Microsoft den Kinect-Sensor im Rahmen eines Softwareupdates mit einem durchaus brauchbaren grammatikbasierten Spracherkennungs-API ausstattete, staunten die Auguren – die Sprachverarbeitung erfolgte damals nämlich ausschließlich auf der Workstation des Entwicklers. Seither nutzt Microsoft die Möglichkeiten der immer verfügbaren Internetverbindung, um Entwickler mehr und mehr in Richtung von (bequem abrechenbaren) Cloud-Services zu treiben. Mit den Azure Cognitive Services steht ein durchaus leistungsfähiges Portfolio von AI-Cloud-Diensten zur Verfügung, die wir uns in den folgenden Schritten anhand einiger kleiner Beispiele kurz ansehen wollen.
Was gibt es?
AI-Start-ups stehen immer im Spannungsfeld zwischen Generalisierung und Spezialisierung. Ist der angebotene Dienst zu generell, muss der Entwickler noch zu viel Arbeit beitragen und ist deshalb nicht wirklich zu seiner Nutzung motiviert. Ist der Dienst allerdings zu speziell, ist die erreichbare Zielgruppe zu klein.
Nach der Reorganisation – die Websuchdienste wurden aus den Azure Cognitive Services in die Bing-APIs ausgelagert – bestehen die Cognitive Services noch aus vier Dienstgruppen, die wir in den Abbildungen 1 bis 4 im Profil vorstellen.
Abb. 1: Decision, …
Abb. 2: … Language, …
Abb. 3: … Speech …
Abb. 4: … und Vision sind der Vierkampf der künstlichen Cloud-Intelligenz im Hause Microsoft
In der Rubrik „Decision“ finden sich dabei Werkzeuge, die aus bereitzustellenden Informationen Entscheidungen ableiten, darunter auch ein als Content Moderator bezeichnetes Modul, das sich um die automatische Ausfilterung von nicht akzeptablem User-generated Content kümmert. In der Rubrik „Language“ finden sich verschiedene Dienste, die sich auf die Verarbeitung von in Form von Strings vorliegenden Texten konzentriert haben. Ein Klassiker ist dabei die Sentiment Analysis, die die vom Schreiber im Text zu vermittelnde Stimmung analysiert. Mit dem Translator steht analog dazu ein Übersetzer zur Verfügung, der Texte in durchaus brauchbarer Qualität zwischen mittlerweile 90 Sprachpaaren hin- und hertransferiert. In der Rubrik „Speech“ findet sich im Allgemeinen das, was man erwarten würde: TTS-Dienste. Seit der Übernahme des Unternehmens Lernout & Hauspie darf Microsoft hier auf die Kompetenz von Dragon zurückgreifen. Zu guter Letzt gibt es in der Rubrik „Vision“ eine ganze Gruppe von Diensten, die sich um angeliefertes Bildmaterial kümmern – neben der (ebenfalls am Kinect erstmals demonstrierten) Emotions- und Gesichtserkennung gibt es auch Systeme, die aus Videos und/oder Bildern Informationen über die in ihnen enthaltenen Elemente darstellen. Kurzum: Wer die Webseite der Azure Cognitive Services [1] besucht, findet jede Menge nützliche Dienste.
Erste Schritte mit Sprache
Jeder der vier Cognitive-Services-Unterdienste ist gleich interessant. Wir wollen in den folgenden Schritten aus Spaß an der Freude mit dem Sprachdienst beginnen. Interessant ist, dass Microsoft die Cognitive Services nicht wirklich zum Boosten der sonstigen hauseigenen Betriebssysteme einsetzt. Abbildung 5 zeigt, dass die Beispiele (und die dazugehörigen SDKs) für verschiedene Plattformen gleichermaßen angeboten werden.
Abb. 5: Microsoft ist in Sachen Plattformzielauswahl nicht sehr wählerisch
Trotzdem wollen wir in den folgenden Schritten mit Visual Studio 2019 arbeiten. Zunächst erbeuten wir eine halbwegs aktuelle Version der Entwicklungsumgebung und erzeugen darin ein neues Projekt auf Basis der Vorlage Leere App (Universelle Windows-App). Im Bereich der Projektnamensvergabe haben wir wie immer freie Hand, der Autor entscheidet sich in den folgenden Schritten für „SUSTalker1“. Im daraufhin erscheinenden Zielauswahldialog ist es wichtig, dass wir in der Rubrik Mindestens erforderliche Version den Wert Windows 10 Fall Creators Update (10.0; Build 16299) oder besser auswählen. Die Microsoft-Speech-Algorithmen kümmern sich nicht wirklich darum, woher wir unsere Toninformationen beziehen. Im Interesse der Bequemlichkeit wollen wir in den folgenden Schritten mit dem (hoffentlich hochqualitativen) Mikrofon unserer Workstation arbeiten, weshalb wir die Manifestdatei unserer Applikation öffnen und nach folgendem Schema ergänzen:
Capabilities>
<Capability Name="internetClient" />
<DeviceCapability Name="microphone"/>
</Capabilities>
eachten Sie, dass die Arbeit mit AI-Spracherkennungssystemen wesentlich stringentere Anforderungen an die Tonqualität stellt als die Arbeit mit Skype und Co. Insbesondere bei Systemen, die für wenig technisch versierte Anwender vorgesehen sind. Lernout & Hauspies Dragon ist ein Klassiker. Es kann sogar empfehlenswert sein, die Verwendung hochqualitativer externer USB-Mikrofone vorzuschreiben. Der Autor arbeitet in den folgenden Schritten mit einem Mikrofon aus dem Hause auna. Der letzte Schritt der Vorbereitungshandlungen auf Applikationsebene ist dann das Aufrufen der NuGet-Paketverwaltung, in der wir uns für das Paket Microsoft.CognitiveServices.Speech entscheiden.
Im nächsten Schritt rufen wir das Azure-Portal auf, in dem wir uns auf die Suche nach dem Microsoft Speech Service begeben. Sein Symbol ist in Abbildung 6 mit einem roten Pfeil markiert. In der Azure-Backend-Verwaltung finden sich mittlerweile Dutzende von AI-Angeboten von Drittherstellern. Wer mit den Azure Cognitive Services arbeiten möchte, ist gut beraten, in der Volltextsuche den mit dem gelben Pfeil hervorgehobenen Filter auf Microsoft zu setzen, um Drittanbieterangebote von vornherein auszuschließen.
Abb. 6: Diese Einstellungen führen zum Ziel
Im Bereich der Namensvergabe haben wir auch hier freie Wahl, der Autor entschied sich in den folgenden Schritten für „SUSSpeechService“. Als Preisebene wollen wir die kostenlose Version F0 auswählen, die für erste Experimente ausreicht.
Weitere Informationen zu den Möglichkeiten und Grenzen der verschiedenen als Pricing Tier bezeichneten Preisstufen finden sich unter [2].Die eigentliche Realisierung eines Text-to-Speech-Prozesses unter der Universal Windows Platform wird dadurch erschwert, dass die von Microsoft bereitgestellte Dokumentation teilweise fehlerhaft ist. Es gibt in der UWP-Version des Speech SDK nämlich noch keinen Weg, um die eigentliche Tonausgabe unter Nutzung der Cognitive-Services-Bibliothek zu erledigen. Aus diesem Grund müssen wir stattdessen nach folgendem Schema mit der Realisierung einiger globaler Member-Variablen beginnen:
public sealed partial class MainPage : Page {
SpeechConfig myConfig;
MediaPlayer mediaPlayer;
Als Nächstes ergänzen wir die XAML-Formulardatei um einen Knopf mit der Aufschrift Speak English, der im Code-Behind mit einem asynchronen Klick-Event-Handler auszustatten ist:
async private void CmdSpeakEnglish_Click(object sender, RoutedEventArgs e)
{
AudioConfig myAudioC = AudioConfig.FromDefaultSpeakerOutput();
var devices = await DeviceInformation.FindAllAsync(DeviceClass.AudioRender);
In der Vollversion des Speech SDKs sorgt die AudioConfig-Klasse für das Routing der vom Server zurückgelieferten Sprachinformationsdateien. Im Interesse der Vollständigkeit wollen wir an dieser Stelle illustrieren, wie wir über alle beim Gerät angemeldeten Audiogeräte iterieren können, um ein bestimmtes über seine ID festzulegen:
foreach (var device in devices){
if (device.Name.Contains("Lautsprecher")) {
myAudioC = AudioConfig.FromSpeakerOutput(device.Id);
}
}
Die nächste idiomatische Amtshandlung des Entwicklers besteht darin, eine SpeechSynthesizer-Instanz anzuwerfen und diese durch Aufruf der Methode SpeakTextAsync zur Kommunikation mit dem Server anzuleiten:
var synthesizer = new SpeechSynthesizer(myConfig, myAudioC);
using (var result = await synthesizer.SpeakTextAsync("SUS sends its best regards")) {
if (result.Reason == ResultReason.SynthesizingAudioCompleted) {
An dieser Stelle findet sich der in der Einleitung dieses Sektors besprochene Dokumentationsbug: Auf anderen Plattformen liefert SpeakTextAsync die vom Server zurückgegebenen Informationen direkt an das Standardausgabegerät der unterliegenden Hardware weiter. In der UWP ist das allerdings nicht möglich, weshalb trotz Zurückgabe des Ergebnisses SynthesizingAudioCompleted keine Audioausgabe erfolgt. Zur Umgehung dieses Problems – Microsoft empfiehlt diese Vorgehensweise übrigens auch im offiziellen UWP-Sample – bietet es sich an, auf einen Mediaplayer zu setzen. Haarig ist dabei nur, dass er eine separat zu erzeugende Eingabedatei erwartet (Listing 1).
Listing 1
using (var audioStream = AudioDataStream.FromResult(result)) {
var filePath = Path.Combine(ApplicationData.Current.LocalFolder.Path, "outputaudio_for_playback.wav");
await audioStream.SaveToWaveFileAsync(filePath);
mediaPlayer.Source = MediaSource.CreateFromStorageFile(await StorageFile.GetFileFromPathAsync(filePath));
mediaPlayer.Play();
}
Zur Fertigstellung des Programms müssen wir uns dann noch die Deklaration der beiden Formular-Member-Variablen zu Gemüte führen:
public MainPage() { . . .
myConfig = SpeechConfig.FromSubscription("KEY", "westeurope");
mediaPlayer = new MediaPlayer();
}
Die SpeechConfig-Instanz ist dabei von besonderer Bedeutung, da sie diverse für das gesamte Programmleben geltende Konstanten festlegt und auch für die Authentication unserer Applikation beim Azure-Server verantwortlich ist. Anstatt des vom Autor hier genutzten Platzhalters müssen Sie den Inhalt der Felder Key 1 oder Key 2 eingeben; der in den zweiten String einzufügende Wert wird vom Azure-Backend netterweise ebenfalls in der Rubrik Location angezeigt.
Danach sind wir mit diesem Beispiel auch schon fertig. Starten Sie es und klicken Sie bei bestehender Internetverbindung auf den Knopf, um sich an der Ausgabe des englischen Samples zu erfreuen. Angemerkt sei noch, dass Sie in der Variable auch ein Array mit Audiodaten bekommen, das Sie zum Beispiel für die Bluetooth-Übertragung an einen Prozessrechner weiterverwenden können.
Exkurs: Mehrsprachigkeit
Wer seinem Programm oder Produkt schnell einen Vorsprung am Markt verschaffen möchte, sollte es nach Möglichkeit lokalisieren. Das ist im Fall von textbasierten Applikationen vergleichsweise einfach, die Lokalisierung von Sprachausgaben stellt den PT-Entwickler allerdings vor immense Zusatzkosten. Microsoft ist sich dieser Situation bewusst, und bietet Dutzende von vorgefertigten Sprachmodellen an [3].
Als kleine Fingerübung wollen wir unser bisher Englisch sprechendes Programm noch auf Schwyzerdütsch umstellen. Hierzu müssen wir die XAML-Datei im ersten Schritt um einen weiteren Knopf ergänzen, den wir – fehlerhaft – mit Speak German betiteln. Im Interesse der Kompaktheit wollen wir den im Allgemeinen vom Englisch-Knopf zu übernehmenden Event Handler nur insofern abdrucken, als er sich von seinem Kollegen unterscheidet (Listing 2).
Listing 2
async private void CmdSpeakGerman_Click(object sender, RoutedEventArgs e)
{
. . .
myConfig.SpeechSynthesisVoiceName = "de-CH-LeniNeural";
var synthesizer = new SpeechSynthesizer(myConfig, myAudioC);
using (var result = await synthesizer.SpeakTextAsync("SUS sendet beste Grüße"))
. . .
Neben der offensichtlichen Änderung des Hinzufügens eines neuen Ausgabetexts legen wir in der globalen Konfiguration über das Attribut myConfig.SpeechSynthesisVoiceName fest, dass fortan Schwyzerdütsch zu verwenden ist. Die MyConfig-Instanz wird dabei witzigerweise mit dem englischen Knopf geteilt, weshalb das Ausführen englischer Sprachausgaben nach der Anpassung des Attributs zu einer recht lustigen Intonation führt.
Sprache in Text umwandeln
Nachdem wir dem Rechner das Sprechen beigebracht haben, wollen wir die weiter oben in die Manifestdatei eingepflegte Berechtigung nun auch zum Hören einspannen. Da Microsoft Googles Versuchung zur Einführung eines aktiven Permission-Managements nicht widerstehen konnte, müssen wir an dieser Stelle eine Gruppe von Steuerelementen hinzufügen. Neben einem Textblock und einem Start– sowie einem Stop-Knopf müssen wir auch einen Mic-Button einfügen, über den der Benutzer das Anfordern der Mikrofonberechtigungen lostritt.
Für die eigentliche Ausgabe der Statusinformationen brauchen wir dann noch die Funktion AppendToLog. An ihr ist eigentlich nur die Verwendung des Dispatchers interessant, der Aktualisierungen der Logging-Textbox auch außerhalb des WPS- bzw. UWP-GUI-Threads erlaubt:
void AppendToLog(String _what) {
Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => {
TxtRaus.Text = TxtRaus.Text + "/ /" + _what;
});
}
Der Code für die Anforderung der Mikrofonberechtigung ist mehr oder weniger gewöhnlicher Boilerplate, der sich in diversen Microsoft-Codebeispielen unverändert wiederfindet (Listing 3).
Listing 3
private async void EnableMicrophone_ButtonClicked(object sender, RoutedEventArgs e)
{
bool isMicAvailable = true;
try {
var mediaCapture = new Windows.Media.Capture.MediaCapture();
var settings = new Windows.Media.Capture.MediaCaptureInitializationSettings();
settings.StreamingCaptureMode = Windows.Media.Capture.StreamingCaptureMode.Audio;
await mediaCapture.InitializeAsync(settings);
}
catch (Exception) {
isMicAvailable = false;
}
Die erste Amtshandlung des Codes besteht darin, eine Medienaufnahmesession bei der UWP anzufordern und dabei das Auftreten von Exceptions zu überprüfen. Dahinter steht die simple Logik, dass das Werfen einer Exception an dieser Stelle darauf hinweist, dass unsere Applikation die benötigte Berechtigung vom Betriebssystem noch nicht zugewiesen bekommen hat. In diesem Fall nutzen wir danach die Funktion LaunchUriAsync, um den Benutzer zur Freigabe der Mikrofonberechtigungen aufzufordern (Listing 4).
Listing 4
if (!isMicAvailable) {
await Windows.System.Launcher.LaunchUriAsync(new Uri("ms-settings:privacy-microphone"));
}
else {
CmdGo.IsEnabled = CmdStop.IsEnabled = true;
}
}
Je nach Konfiguration der Runtime wird die Workstation darauf entweder mit dem einmaligen oder aber mit dem mehrmaligen Einblenden eines Permission-Dialogs reagieren. Wichtig ist hier nur noch, dass wir die Start– und die Stop-Knöpfe für die Sprachaufnahme nur dann aktivieren, wenn die Methode das Vorhandensein der Mikrofonzugriffsberechtigung angezeigt hat. Sonst orientiert sich SpeechRecognizer – zumindest kontextuell – an seinem für die Sprachausgabe vorgegebenen Kollegen. Auch hier gilt, dass wir eine globale Instanz vom Typ SpeechRecognizer benötigen (Listing 5).
Listing 5
SpeechRecognizer myRecWorker;
async private void CmdGo_Click(object sender, RoutedEventArgs e)
{
AudioConfig myAudioC = AudioConfig.FromDefaultMicrophoneInput();
var devices = await DeviceInformation.FindAllAsync(DeviceClass.AudioCapture);
foreach (var device in devices)
{
if (device.Name.Contains("Anua"))
{
myAudioC = AudioConfig.FromSpeakerOutput(device.Id);
}
}
Da die Workstation des Autors, wie übrigens die meisten Rechner, auch einen analogen Mikrofoneingang hat, „sucht“ er auch hier anhand des Gerätenamens nach seinem Mikrofon. Der dazu verwendete Code unterscheidet sich nur insofern vom weiter oben verwendeten Kollegen, als wir an FindAllAsync nun das Attribut DeviceClass.AudioCapture übergeben. Das permanente Betonen dieser „dedizierten“ Geräteauswahl ist dabei übrigens keine Marotte des Autors, denn wer sie nicht implementiert, riskiert furiose Benutzerwertungen. Das Unbequemsein dieser Einrichtung ist – zumindest nach Meinung des Autors – auch einer der Gründe, warum die Weboberfläche von Microsoft Teams so universell verhasst ist.
Die nächste Gemeinsamkeit mit der Ausgabeversion der Klasse findet sich bei der Konfiguration der zu verwendenden Sprache. Sie erfolgt ebenfalls in dem globalen Einstellungsobjekt, das sich auch um das Einrichten der Azure Authentication kümmert:
myConfig.SpeechRecognitionLanguage = "de-DE";
Grammatikfreier Sprechfluss
Im Bereich der computerbasierten Spracherkennungssysteme gibt es seit jeher einen Kampf zwischen grammatikbasierten und frei arbeitenden Versionen. Die in den Azure Cognitive Services implementierte Spracherkennungs-Engine arbeitet dabei analog zu Lernout & Hauspies Dragon ohne Grammatik, weshalb sie potenziell beliebig lange Ein- und Ausgabeströme verarbeiten kann.
Da Entwickler in der Praxis aber auch immer wieder das Bedürfnis haben, kürzere Kommandos zu verarbeiten, implementiert Microsoft zwei verschiedene Versionen des APIs. Wir wollen hier schon aus Gründen der Bequemlichkeit mit dem Vollausbau beginnen, was den in Listing 6 gezeigten Code im Start-Knopf voraussetzt.
Listing 6
myRecWorker = new SpeechRecognizer(myConfig, myAudioC);
myRecWorker.Canceled += MyRecWorker_Canceled;
myRecWorker.SpeechEndDetected += MyRecWorker_SpeechEndDetected;
myRecWorker.Recognized += MyRecWorker_Recognized;
myRecWorker.SpeechStartDetected += MyRecWorker_SpeechStartDetected;
myRecWorker.SessionStarted += MyRecWorker_SessionStarted;
myRecWorker.StartContinuousRecognitionAsync();
AppendToLog("LOS!");
}
Die Funktion StartContinuousRecognitionAsync weist das SDK dabei darauf hin, dass es ab sofort in den „permanenten“ Spracherkennungsmodus wechseln soll. Dabei bekommt der Entwickler kein finales Resultat zurückgeliefert, sondern muss stattdessen eine Gruppe von Event Handlern einschreiben, die permanent vom Server angelieferte Ereignisse aufnehmen.
Der Autor realisiert hier nur einige der Handler, eine Liste aller exponierten Ereignisse findet sich am einfachsten durch Reflexion. Am wichtigsten ist im Bereich der Event-Handler-Kohorte die Verarbeitung des Canceled-Events, die nach folgendem Schema zu erfolgen hat:
private void MyRecWorker_Canceled(object sender, SpeechRecognitionCanceledEventArgs e){
AppendToLog("Canceled! " + e.ErrorDetails);
}
Das Azure-Backend liefert unserer Applikation immer dann ein Canceled-Ereignis, wenn es die Datenverarbeitung final einstellt. In den diversen Attributen des SpeechRecognitionCanceledEventArgs-Objekts finden sich dann Informationen darüber, warum unsere Applikation das Missfallen des Servers provoziert hat. Aus der weiteren praktischen Erfahrung des mit einer Dual-Boot-Workstation arbeitenden Autors sei angemerkt, dass die Korrektheit des in Windows eingestellten Systemdatums für die Cognitive Services von größter Bedeutung ist. Wer versehentlich einen falschen Datumswert – schon ein oder zwei Stunden Unterschied reichen aus – einstellt, wird vom Server mit diversen „Connection Refused“-Ereignissen abgestraft.
Relevant ist dann noch das Event Recognized, das die Services immer dann abfeuert, wenn aus der Sprachsequenz ein kompletter String erkannt wurde. Zu seiner Verarbeitung reicht folgender Code aus, der die angelieferten Informationen zudem bequem in den weiter oben angelegten Textblock wirft:
private void MyRecWorker_Recognized(object sender, SpeechRecognitionEventArgs e) {
AppendToLog("Erbeutetes Ergebnis: " + e.Result.Text);
}
Beim erstmaligen Bring-up verschiedener komplizierter Softwaresysteme ist es erfahrungsgemäß empfehlenswert, diverse andere Status-Events zu exponieren, um mehr Informationen über Interaktion und Programmverhalten zu bekommen. Die restlichen weiter oben abgedruckten Ereignisse sind mit nach dem folgenden Schema aufgebauten Handlern verbunden, die sich um das Ausspeien zusätzlicher Statusinformationen kümmern:
private void MyRecWorker_SpeechEndDetected(object sender, RecognitionEventArgs e) {
AppendToLog("Redepause!");
}
Zum „kompletten“ Spracherkennungsprogramm fehlt uns dann nur noch eine Implementierung des Stop-Knopfes, der den Server von der weiteren Entgegennahme von Mikrofondaten befreit. Seine Implementierung ist schon aus dem Grund erforderlich, weil sonst nicht unerhebliche Kosten entstehen:
private void CmdStop_Click(object sender, RoutedEventArgs e) {
myRecWorker.StopContinuousRecognitionAsync();
}
An dieser Stelle können wir unser Programm zur Ausführung freigeben. Wer es, wie der Autor, testweise mit dem String „Hallo Welt“ ausstattet, bekommt das in Abbildung 7 gezeigte Ergebnis präsentiert.
Abb. 7: Die Spracherkennung unter Nutzung der Cognitive Services funktioniert problemlos
Für alle ASP.NET-Core-basierten Anwendungsarten hat Microsoft begonnen, die ASP.NET-Core-Klassen für die bessere Unterstützung der in C# 8.0 eingeführten Nullable Reference Types zu annotieren.
Die in Blazor 5.0 eingeführte CSS-Isolation (Beschränkung der Gültigkeit auf einzelne .razor-Komponenten) funktioniert in .NET 6 auch mit den älteren Multi-Page-Programmiermodellen Model View Controller (MVC) und Razor Pages. IAsyncDisposable funktioniert nun für Controller, Page Models und View Components.
Exkurs: Und jetzt in klein
Wir hatten weiter oben festgestellt, dass Microsoft auch eine „reduzierte“ Version der Spracherkennungs-Engine anbietet. Sie arbeitet nach dem Prinzip, dass sie so lange „zuhört“, bis eine Endbedingung erkannt wird. Legitime Endbedingungen sind dabei einerseits das Aufhören des Redeflusses und andererseits das Ablaufen von fünfzehn Sekunden nach dem Aufnahmestart.
Kommt Ihre Applikation mit einem derartig beschränkten Funktionsumfang aus, so lässt sich die Konfiguration des Listeners nach dem in Listing 7 gezeigten Schema stark vereinfachen.
Listing 7
var result = await recognizer.RecognizeOnceAsync().ConfigureAwait(false);
string str;
if (result.Reason != ResultReason.RecognizedSpeech) {
str = $"Speech Recognition Failed. '{result.Reason.ToString()}'";
}
else {
str = $"Recognized: '{result.Text}'";
}
Bei derartigen einfachen Spracherkennungsaufgaben geht es oft darum, bestimmte Kommandos besonders effizient zu erreichen. Microsoft unterstützt dieses Begehr insofern, als wir der an sich grammatikfreien Spracherkennungslogik einige benutzerspezifizierte Worte einschreiben können, die die Engine danach als besonders häufig auftretend betrachtet. Zur Nutzung dieser Sonderfunktion ist ein folgendermaßen aufgebauter Code erforderlich:
var phraseList = PhraseListGrammar.FromRecognizer(recognizer); phraseList.AddPhrase("Supercalifragilisticexpialidocious");
Fazit
Auch wenn der Gedanke an die Auslagerung von ML-Modellen in die Cloud auf den ersten Blick angesichts der Mietkosten wenig einladend erscheint, lohnt es sich trotzdem, einen zweiten Gedanken darauf zu verschwenden. Die von Microsoft bereitgestellten ML-Modelle erreichen unglaubliche Güteklassen, die hier durchgeführten Spracherkennungsversuche erreichten in Tests die Genauigkeit der von Lernout & Hauspie für teures Geld verkauften Erkennungs-Engine Dragon – und das, ohne dass der Autor die Services vorher, wie bei Dragon erforderlich, auf die eigene Sprache trainiert hätte.
Links & Literatur
[1] https://azure.microsoft.com/en-us/services/cognitive-services/#features